package com.caow.baselibrary

import android.app.Application
import androidx.lifecycle.*
import com.caow.baselibrary.bean.BizResult
import com.caow.baselibrary.utils.LogUtils
import com.caow.baselibrary.utils.ToastUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.core.KoinComponent
import retrofit2.HttpException

/**
 * @Author caow
 * 2022/11/18
 */
open class BaseViewModel(app: Application) : AndroidViewModel(app), KoinComponent,
    LifecycleObserver {

    protected val TAG by lazy { javaClass.simpleName }

    // 加载中弹窗
    internal val showLoadingDialog by lazy { MutableLiveData<Any?>() }
    internal val dismissLoadingDialog by lazy { MutableLiveData<Any?>() }

    val closeActivity = MutableLiveData<Any?>()

    /**
     * 所有网络请求都在 viewModelScope 域中启动，当页面销毁时会自动
     * 调用ViewModel的  #onCleared 方法取消所有协程
     */
    fun launchUI(block: suspend CoroutineScope.() -> Unit) = viewModelScope.launch { block() }

    /**
     *  不过滤请求结果
     * @param block 请求体
     * @param error 失败回调
     * @param complete  完成回调（无论成功失败都会调用）
     * @param isShowDialog 是否显示加载框
     */
    fun launchGo(
        block: suspend CoroutineScope.() -> Unit,
        error: suspend CoroutineScope.(Exception) -> Unit = {
            it.message?.let { str ->
                ToastUtils.show(str)
                LogUtils.e("BaseViewModel", str)
            }
//            dismissLoading()
        },
        complete: suspend CoroutineScope.() -> Unit = {},
        isShowDialog: Boolean = true
    ) {
        if (isShowDialog) showLoading()
        launchUI {
            handleException(
                withContext(Dispatchers.IO) { block },
                { error(it) },
                {
                    if (isShowDialog) dismissLoading()
                    complete()
                }
            )
        }
    }

    /**
     * 没写完
     */
    fun <T> launchNet(
        net: suspend CoroutineScope.() -> BizResult<T>,
        block: suspend CoroutineScope.(T) -> Unit,
        netError: suspend CoroutineScope.(Int, String?) -> Unit = { code, msg ->
            msg?.let { ToastUtils.show(it) }
        },
        error: suspend CoroutineScope.(Exception) -> Unit = {},
        complete: suspend CoroutineScope.() -> Unit = {},
        isShowDialog: Boolean = true
    ) {
        if (isShowDialog) showLoading()
        launchUI {
            try {
                val result = net()
                if (result.success) {
                    block(result.data)
                } else {
//                    netError(result.)
                }
            } catch (e: Throwable) {
                error(Exception(e))
            } finally {
                complete()
            }
        }
    }

    /**
     * 异常统一处理
     */
    private suspend fun handleException(
        block: suspend CoroutineScope.() -> Unit,
        error: suspend CoroutineScope.(Exception) -> Unit,
        complete: suspend CoroutineScope.() -> Unit
    ) {
        launchUI {
            try {
                block()
            } catch (e: Throwable) {
                if (e is HttpException) {
                    error(e)
                } else {
                    error(Exception(e))
                }
            } finally {
                complete()
            }
        }
    }

    fun showLoading() {
        showLoadingDialog.postValue(null)
    }

    fun dismissLoading() {
        dismissLoadingDialog.postValue(null)
    }

    fun finish() {
        closeActivity.postValue(null)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    open fun onCreate() {
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    open fun onResume() {
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    open fun onDestroy() {
    }
}